package com.ruoyi.well.mqtt;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;


import com.ruoyi.permission.mapper.SerDevicePermiMapper;
import com.ruoyi.permission.service.PermiService;

import com.ruoyi.well.domain.SerWellDevice;
import com.ruoyi.well.domain.SerWellLog;
import com.ruoyi.well.mapper.SerWellDeviceMapper;
import com.ruoyi.well.mapper.SerWellLogMapper;
import com.ruoyi.xag.mapper.DeviceMapper;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.IOUtils;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.concurrent.CompletableFuture;

@Component
public class PushCallback implements MqttCallback {
    private static final Logger logger = LoggerFactory.getLogger(MqttPushClient.class);

    @Autowired
    private MqttConfig mqttConfig;
    @Autowired
    private PermiService permiService;
    @Autowired
    private SerDevicePermiMapper devicePermiMapper;
    @Autowired
    private MqttPushClient mqttPushClient;
    @Autowired
    private SerWellDeviceMapper wellDeviceMapper;
    @Autowired
    private SerWellLogMapper wellLogMapper;
    /**
     * 存储文件的路径
     */
    @Value("${ruoyi.profile}")
    private String profile;
    private static MqttClient client;

    private static String _topic;
    private static String _qos;
    private static String _msg;

    @Override
    public void connectionLost(Throwable throwable) {
        // 连接丢失后，一般在这里面进行重连
        logger.info("连接断开，可以做重连");
        if (client == null || !client.isConnected()) {
            mqttConfig.getMqttPushClient();
        }
    }

    @Override
    public void messageArrived(String topic, MqttMessage mqttMessage) {
        CompletableFuture.runAsync(() -> {
            try {
                // 处理接收到的消息
                HashMap resMap = handleReceivedMessage(topic, mqttMessage);
                String response = (String) resMap.get("Response");
                String devId = (String) resMap.get("DevId");
                String pTopic = "/msyc/xingyou/" + devId +"/command";
//                logger.info("pTopic====" + pTopic);
                // 如果需要，在这里添加发布响应消息的逻辑
                publishResponse(pTopic, response);
            } catch (Exception e) {
                // 处理异常
            }
        });
    }


    public HashMap handleReceivedMessage(String topic, MqttMessage mqttMessage) throws Exception {
        // subscribe后得到的消息会执行到这里面
        logger.info("接收消息主题 : " + topic);
        logger.info("接收消息Qos : " + mqttMessage.getQos());
        logger.info("接收消息内容 : " + new String(mqttMessage.getPayload()));
        _topic = topic;
        _qos = mqttMessage.getQos() + "";
        _msg = new String(mqttMessage.getPayload());
        /*
         *  在这里添加处理接收到主题的代码
         *  屎山开堆 ！！
         *
         */
//        接收上传参数
        HashMap resMap = new HashMap<>();
//            将消息转换为json格式
        if(topic.equals("xingyou")) {
            resMap.clear();
            String response = "";
            JSONObject msgJsonObject = JSONObject.parseObject(_msg);
            String type = msgJsonObject.getString("Type");
            logger.info("通讯类型" + type);
            String deviceId = msgJsonObject.getString("DeviceId");
            switch (type) {
//                初始化链接
                case "DATA":
                    JSONObject DATA_data = msgJsonObject.getJSONObject("data");
                    Double e_vol = DATA_data.getDouble("e_vol");
                    Double w_vol = DATA_data.getDouble("w_vol");
                    Double signal = DATA_data.getDouble("Signal");
                    Double longitude = DATA_data.getDouble("longitude");
                    Double latitude = DATA_data.getDouble("latitude");
                    String CCID = DATA_data.getString("CCID");
                    SerWellDevice serWellDevice = new SerWellDevice().setDeviceId(deviceId).setElectricVol(e_vol).setWaterVol(w_vol)
                            .setSignal(signal).setLongitude(longitude).setLatitude(latitude).setSimId(CCID);
                    if(wellDeviceMapper.selectByPrimaryKey(deviceId)!=null){
                        wellDeviceMapper.updateByPrimaryKeySelective(serWellDevice);
                    }else {
                        wellDeviceMapper.insertSelective(serWellDevice);
                    }
                    response = String.format("{\"type\":\"DATA_RETURN\",\"DataResult\":\"1\",\"MSG\":\"\"}");
//                    logger.info("接收正常：" + mqttPushClient.publish(0, false, "xingyou_return", dataReturn));
                    break;
                    // 心跳包
                case "heart":
                    //数据处理
                    //客户端未连接时的参数
                    JSONObject heart_data = msgJsonObject.getJSONObject("data");
                    Double w_lev = heart_data.getDouble("w_lev");
                    Double w_pre = heart_data.getDouble("w_pre");
                    Double soil1 = null;
                    Double soil2 = null;
                    Double soil3 = null;
                    Double soil4 = null;
                    if (heart_data.containsKey("soil1")) {
                        soil1 = heart_data.getDouble("soil1");
                    }
                    if (heart_data.containsKey("soil2")){
                        soil2 = heart_data.getDouble("soil2");
                    }
                    if (heart_data.containsKey("soil3")){
                        soil3 = heart_data.getDouble("soil3");
                    }
                    if (heart_data.containsKey("soil4")){
                        soil4 = heart_data.getDouble("soil4");
                    }
                    /**********************************************************/
                    //开井后的心跳包的参数
                    Integer sta = null;
                    Double heart_e_vol = null;
                    Double heart_w_vol = null;
                    Double w_ins = null;
                    Double c_bal = null;
                    String c_num = null;
                    //-1表示是未开井的心跳内容处理  0表示开井后的心跳包内容处理失败  1表示开井后的心跳包内容处理成功
                    int flag = -1;
                    //若开井，十分钟会上传以下信息，则十分钟更新一次well_log对应的日志
                    if (heart_data.containsKey("sta")) {
                        sta = heart_data.getString("sta").equals("on")?1:0;
                        heart_e_vol = heart_data.getDouble("e_vol");
                        heart_w_vol = heart_data.getDouble("w_vol");
                        w_ins = heart_data.getDouble("w_ins");
                        c_bal = heart_data.getDouble("c_bal");
                        c_num = heart_data.getString("c_num");
                        SerWellLog serWellLog = new SerWellLog().setDeviceId(deviceId).setCardNum(c_num).setCardBal(c_bal).setElectricVol(heart_e_vol).setWaterVol(heart_w_vol);

                        //找出对应还未关井的机井
                        List<SerWellLog> selectWellLogList = wellLogMapper.selectByDeviceId(deviceId);
                        //找到未关井的设备，对应的日志进行更新
                        for(SerWellLog selectSerWellLog:selectWellLogList){
                            if(selectSerWellLog.getIsOff()==0){
                                Integer id = selectSerWellLog.getId();
                                serWellLog.setId(id);
                                flag = wellLogMapper.updateByPrimaryKeySelective(serWellLog);
                                break;
                            }
                        }
                    }
                    SerWellDevice serWellDeviceHeart = new SerWellDevice().setDeviceId(deviceId).setWaterLev(w_lev).setWaterPre(w_pre).setSoil1(soil1).setSoil2(soil2)
                            .setSoil3(soil3).setSoil4(soil4).setStatus(sta).setWaterIns(w_ins).setUpdateTime(new Date());
                    int i = wellDeviceMapper.updateByPrimaryKeySelective(serWellDeviceHeart);
                    if(i>0 && flag!=-1){
                        response = String.format("{\"type\":\"HEART_RETURN\",\"DataResult\":\"0\",\"MSG\":\"\"}");
//                        logger.info("接收正常：" + mqttPushClient.publish(0, false, "xingyou_return", heartReturn));
                    }else{
                        response = String.format("{\"type\":\"HEART_RETURN\",\"DataResult\":\"1\",\"MSG\":\"well not exist\"}");
//                        logger.info("接受处理异常" + mqttPushClient.publish(0, false, "xingyou_return", heartReturn));
                    }
                    break;
//                    刷用户卡开井
                case "user":
                    JSONObject user_card = msgJsonObject.getJSONObject("card");
                    String sta_user = user_card.getString("sta");
                    String c_num_user = user_card.getString("c_num");
                    Integer area_id = user_card.getInteger("area_id");
                    Double c_bal_user = user_card.getDouble("c_bal");
                    if(sta_user.equals("on")){
                        Date onTime = new Date();
                        SerWellLog serWellLog = new SerWellLog().setDeviceId(deviceId).setCardNum(c_num_user).setCardBal(c_bal_user).setAreaId(area_id)
                                .setOnTime(onTime).setInsertTime(onTime).setIsOff(0);
                        wellLogMapper.insertSelective(serWellLog);
                        response = String.format("{\"type\":\"USER_RETURN\",\"DataResult\":\"0\",\"MSG\":\"\"}");
//                        logger.info("接收正常" + mqttPushClient.publish(0, false, "xingyou_return", userReturn));
                    }
//                    刷用户卡关井，获取本次卡用量
                    else if (sta_user.equals("off")) {
                        Double user_e_vol = user_card.getDouble("e_vol");
                        Double user_w_vol = user_card.getDouble("w_vol");
                        Date offTime = new Date();
                        SerWellLog serWellLog = new SerWellLog().setDeviceId(deviceId).setCardNum(c_num_user).setCardBal(c_bal_user).setAreaId(area_id)
                                .setElectricVol(user_e_vol).setWaterVol(user_w_vol).setOffTime(offTime).setIsOff(1);
                        int flag_user = 0;
                        //找出对应还未关井的机井
                        List<SerWellLog> selectWellLogList = wellLogMapper.selectByDeviceId(deviceId);
                        //找到未关井的设备，进行更新
                        for(SerWellLog selectSerWellLog:selectWellLogList){
                            if(selectSerWellLog.getIsOff()==0){
                                Integer id = selectSerWellLog.getId();
                                serWellLog.setId(id);
                                flag_user = wellLogMapper.updateByPrimaryKeySelective(serWellLog);
                                break;
                            }
                        }
                        if(flag_user == 1){
                            response = String.format("{\"type\":\"USER_RETURN\",\"DataResult\":\"0\",\"MSG\":\"\"}");
//                            logger.info("接收正常" + mqttPushClient.publish(0, false, "xingyou_return", userReturn));
                        }else {
                            response = String.format("{\"type\":\"USER_RETURN\",\"DataResult\":\"1\",\"MSG\":\"well not open\"}");
//                            logger.info("接收处理异常" + mqttPushClient.publish(0, false, "xingyou_return", userReturn));
                        }
                    }
                    break;
            }
            resMap.put("DevId", deviceId);
            resMap.put("Response", response);
            return resMap;
        }else {
            resMap.put("DevId","");
            resMap.put("Response","");
            return resMap;
        }
    }
    private void publishResponse(String topic,String response){
        if(!response.isEmpty()){
            mqttPushClient.publish(0,false,topic,response);
        }
    }
    /**
     * 将JSONArray转换为ArrayList
     * @param jsonArray
     * @return
     */
    private List<String> jsonArrayToList(JSONArray jsonArray) {
        List<String> list = new ArrayList<>();

        for (int i = 0; i < jsonArray.size(); i++) {
            try {
                // JSONArray 中的元素可能是不同类型的对象，这里以整数为例
                String value = jsonArray.getString(i);
                list.add(value);
            } catch (JSONException e) {
                e.printStackTrace();
                // 处理异常，例如元素不是整数类型
            }
        }
        return list;
    }

    public String num2version(Integer versionNum) {
        Integer bai = versionNum / 100;
        Integer ge = versionNum % 10;
        Integer shi = versionNum - bai - ge;
        return bai+","+shi+","+ge;
    }


    @Override
    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
        logger.info("deliveryComplete---------" + iMqttDeliveryToken.isComplete());
    }

    //别的Controller层会调用这个方法来  获取  接收到的硬件数据
    public String receive() {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("topic", _topic);
        jsonObject.put("qos", _qos);
        jsonObject.put("msg", _msg);
        return jsonObject.toString();
    }
    // 第二种方式
    public static MultipartFile getMultipartFile(File file) {
        FileItem item = new DiskFileItemFactory().createItem("file"
                , MediaType.MULTIPART_FORM_DATA_VALUE
                , true
                , file.getName());
        try (InputStream input = new FileInputStream(file);
             OutputStream os = item.getOutputStream()) {
            // 流转移
            IOUtils.copy(input, os);
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid file: " + e, e);
        }

        return new CommonsMultipartFile(item);

    }


}
